home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus Leser 15 / Amiga Plus Leser CD 15.iso / Tools / Development / MosaicSRC / libwww2 / HTMIME.c < prev    next >
Encoding:
C/C++ Source or Header  |  2002-03-13  |  14.0 KB  |  594 lines

  1. /*            MIME Message Parse            HTMIME.c
  2. **            ==================
  3. **
  4. **    This is RFC 1341-specific code.
  5. **    The input stream pushed into this parser is assumed to be
  6. **    stripped on CRs, ie lines end with LF, not CR LF.
  7. **    (It is easy to change this except for the body part where
  8. **    conversion can be slow.)
  9. **
  10. ** History:
  11. **       Feb 92    Written Tim Berners-Lee, CERN
  12. **
  13. */
  14. #include "HTMIME.h"             /* Implemented here */
  15. #include "HTAlert.h"
  16. #include "HTFile.h"
  17. #include "tcp.h"
  18.  
  19. /* This is UGLY. */
  20. char *redirecting_url = NULL;
  21.  
  22. /* This is almost as ugly. */
  23. extern int loading_length;
  24.  
  25. /* #define TRACE 1 */
  26.  
  27. /*        MIME Object
  28. **        -----------
  29. */
  30. typedef enum _MIME_state
  31. {
  32.   BEGINNING_OF_LINE,
  33.   CONTENT_,
  34.   CONTENT_T,
  35.   CONTENT_TRANSFER_ENCODING,
  36.   CONTENT_TYPE,
  37.   CONTENT_ENCODING,
  38.   CONTENT_LENGTH,
  39.   LOCATION,
  40.   SKIP_GET_VALUE,        /* Skip space then get value */
  41.   GET_VALUE,            /* Get value till white space */
  42.   JUNK_LINE,            /* Ignore the rest of this folded line */
  43.   NEWLINE,            /* Just found a LF .. maybe continuation */
  44.   CHECK,            /* check against check_pointer */
  45.   MIME_TRANSPARENT,        /* put straight through to target ASAP! */
  46.   MIME_IGNORE,            /* ignore entire file */
  47.   /* TRANSPARENT and IGNORE are defined as stg else in _WINDOWS */
  48. } MIME_state;
  49.  
  50. #define VALUE_SIZE 256        /* @@@@@@@ Arbitrary? */
  51. struct _HTStream
  52. {
  53.   CONST HTStreamClass * isa;
  54.  
  55.   MIME_state        state;        /* current state */
  56.   MIME_state        if_ok;        /* got this state if match */
  57.   MIME_state        field;        /* remember which field */
  58.   MIME_state        fold_state;    /* state on a fold */
  59.   CONST char *        check_pointer;    /* checking input */
  60.  
  61.   char *        value_pointer;    /* storing values */
  62.   char            value[VALUE_SIZE];
  63.  
  64.   HTParentAnchor *    anchor;     /* Given on creation */
  65.   HTStream *        sink;        /* Given on creation */
  66.  
  67.   char *        boundary;    /* For multipart */
  68.  
  69.   HTFormat        encoding;    /* Content-Transfer-Encoding */
  70.   char *        compression_encoding;
  71.   int            content_length;
  72.   HTFormat        format;     /* Content-Type */
  73.   HTStream *        target;     /* While writing out */
  74.   HTStreamClass     targetClass;
  75.  
  76.   HTAtom *        targetRep;    /* Converting into? */
  77.  
  78.   char *        location;
  79.   int interrupted;
  80. };
  81.  
  82.  
  83. /*_________________________________________________________________________
  84. **
  85. **            A C T I O N    R O U T I N E S
  86. */
  87.  
  88. /*    Character handling
  89. **    ------------------
  90. **
  91. **    This is a FSM parser which is tolerant as it can be of all
  92. **    syntax errors.    It ignores field names it does not understand,
  93. **    and resynchronises on line beginnings.
  94. */
  95.  
  96. PRIVATE void HTMIME_put_character ARGS2(HTStream *, me, char, c)
  97. {
  98.   switch(me->state)
  99.     {
  100.     case MIME_IGNORE:
  101.       if (TRACE)
  102.     fprintf (stderr, "[HTMIME_put_character] Got MIME_IGNORE; returning...\n");
  103.       return;
  104.  
  105.     case MIME_TRANSPARENT:
  106.       (*me->targetClass.put_character)(me->target, c);    /* MUST BE FAST */
  107.       return;
  108.  
  109.     case NEWLINE:
  110.       if (c != '\n' && WHITE(c))
  111.     {
  112.       /* Folded line */
  113.       me->state = me->fold_state;    /* pop state before newline */
  114.       break;
  115.     }
  116.       /* else Falls through */
  117.  
  118.     case BEGINNING_OF_LINE:
  119.       switch(c)
  120.     {
  121.     case 'c':
  122.     case 'C':
  123.       me->check_pointer = "ontent-";
  124.       me->if_ok = CONTENT_;
  125.       me->state = CHECK;
  126.       if (TRACE)
  127.         fprintf (stderr,
  128.              "[MIME] Got C at beginning of line; checking for 'ontent-'\n");
  129.       break;
  130.     case 'l':
  131.     case 'L':
  132.       me->check_pointer = "ocation:";
  133.       me->if_ok = LOCATION;
  134.       me->state = CHECK;
  135.       if (TRACE)
  136.         fprintf (stderr,
  137.              "[MIME] Got L at beginning of line\n");
  138.       break;
  139.     case '\n':                      /* Blank line: End of Header! */
  140.       {
  141.         int compressed = COMPRESSED_NOT;
  142.         if (TRACE)
  143.           fprintf (stderr,
  144.                "HTMIME: DOING STREAMSTACK: MIME content type is %s, converting to %s\n",
  145.                HTAtom_name(me->format), HTAtom_name(me->targetRep));
  146.         if (TRACE)
  147.           fprintf (stderr,
  148.                "                           Compression encoding '%s'\n",
  149.                me->compression_encoding ? me->compression_encoding : "<none>");
  150.         if (me->compression_encoding)
  151.           {
  152.         if (strcmp (me->compression_encoding, "x-compress") == 0)
  153.           {
  154.             compressed = COMPRESSED_BIGZ;
  155.           }
  156.         else if (strcmp (me->compression_encoding, "x-gzip") == 0)
  157.           {
  158.             compressed = COMPRESSED_GNUZIP;
  159.           }
  160.         else
  161.           {
  162.             if (TRACE)
  163.               fprintf (stderr, "HTMIME: Unknown compression_encoding '%s'\n",
  164.                    me->compression_encoding);
  165.           }
  166.           }
  167.  
  168.         if (TRACE)
  169.           fprintf (stderr, "HTMIME: compressed == %d\n", compressed);
  170.         me->target = HTStreamStack(me->format, me->targetRep, compressed,
  171.                        me->sink, me->anchor);
  172.         if (!me->target)
  173.           {
  174.         if (TRACE)
  175.           {
  176.             fprintf(stderr, "MIME: Can't translate! ** \n");
  177.             fprintf(stderr, "HTMIME: Defaulting to HTML.\n");
  178.           }
  179.         /* Default to HTML. */
  180.         me->target = HTStreamStack(HTAtom_for("text/html"),
  181.                        me->targetRep,
  182.                        compressed,
  183.                        me->sink,
  184.                        me->anchor);
  185.           }
  186.         if (me->target)
  187.           {
  188.         me->targetClass = *me->target->isa;
  189.         /* Check for encoding and select state from there @@ */
  190.         /* From now push straigh through */
  191.         if (TRACE)
  192.           fprintf (stderr, "[MIME] Entering MIME_TRANSPARENT\n");
  193.         me->state = MIME_TRANSPARENT;
  194.           }
  195.         else
  196.           {
  197.         /* This is HIGHLY EVIL -- the browser WILL BREAK
  198.            if it ever reaches here.  Thus the default to
  199.            HTML above, which should always happen... */
  200.         if (TRACE)
  201.           fprintf (stderr, "MIME: HIT HIGHLY EVIL!!! ***\n");
  202.         me->state = MIME_IGNORE;        /* What else to do? */
  203.           }
  204.       }
  205.       break;
  206.  
  207.     default:
  208.       if (TRACE)
  209.         fprintf (stderr, "[MIME] Got nothing at beginning of line; bleah.\n");
  210.       goto bad_field_name;
  211.       break;
  212.  
  213.     } /* switch on character */
  214.       break;
  215.  
  216.     case CHECK:             /* Check against string */
  217.       if (TOLOWER(c) == *(me->check_pointer)++)
  218.     {
  219.       if (!*me->check_pointer)
  220.         me->state = me->if_ok;
  221.     }
  222.       else
  223.     {        /* Error */
  224.       if (TRACE)
  225.         fprintf(stderr,
  226.             "HTMIME: Bad character `%c' found where `%s' expected\n",
  227.             c, me->check_pointer - 1);
  228.       goto bad_field_name;
  229.     }
  230.       break;
  231.  
  232.     case CONTENT_:
  233.       if (TRACE)
  234.     fprintf (stderr,
  235.          "[MIME] in case CONTENT_\n");
  236.       switch(c)
  237.     {
  238.     case 't':
  239.     case 'T':
  240.       me->state = CONTENT_T;
  241.       if (TRACE)
  242.         fprintf (stderr,
  243.              "[MIME] Was CONTENT_, found T, state now CONTENT_T\n");
  244.       break;
  245.  
  246.     case 'e':
  247.     case 'E':
  248.       me->check_pointer = "ncoding:";
  249.       me->if_ok = CONTENT_ENCODING;
  250.       me->state = CHECK;
  251.       if (TRACE)
  252.         fprintf (stderr,
  253.              "[MIME] Was CONTENT_, found E, checking for 'ncoding:'\n");
  254.       break;
  255.  
  256.     case 'l':
  257.     case 'L':
  258.       me->check_pointer = "ength:";
  259.       me->if_ok = CONTENT_LENGTH;
  260.       me->state = CHECK;
  261.       if (TRACE)
  262.         fprintf (stderr,
  263.              "[MIME] Was CONTENT_, found L, checking for 'ength:'\n");
  264.       break;
  265.  
  266.     default:
  267.       if (TRACE)
  268.         fprintf (stderr,
  269.              "[MIME] Was CONTENT_, found nothing; bleah\n");
  270.       goto bad_field_name;
  271.  
  272.     } /* switch on character */
  273.       break;
  274.  
  275.     case CONTENT_T:
  276.       if (TRACE)
  277.     fprintf (stderr,
  278.          "[MIME] in case CONTENT_T\n");
  279.       switch(c)
  280.     {
  281.     case 'r':
  282.     case 'R':
  283.       me->check_pointer = "ansfer-encoding:";
  284.       me->if_ok = CONTENT_TRANSFER_ENCODING;
  285.       me->state = CHECK;
  286.       if (TRACE)
  287.         fprintf (stderr,
  288.              "[MIME] Was CONTENT_T; going to check for ansfer-encoding:\n");
  289.       break;
  290.  
  291.     case 'y':
  292.     case 'Y':
  293.       me->check_pointer = "pe:";
  294.       me->if_ok = CONTENT_TYPE;
  295.       me->state = CHECK;
  296.       if (TRACE)
  297.         fprintf (stderr, "[MIME] Was CONTENT_T; going to check for pe:\n");
  298.       break;
  299.  
  300.     default:
  301.       if (TRACE)
  302.         fprintf (stderr,
  303.              "[MIME] Was CONTENT_T; found nothing; bleah\n");
  304.       goto bad_field_name;
  305.     } /* switch on character */
  306.       break;
  307.  
  308.     case CONTENT_TYPE:
  309.     case CONTENT_TRANSFER_ENCODING:
  310.     case CONTENT_ENCODING:
  311.     case CONTENT_LENGTH:
  312.       me->field = me->state;        /* remember it */
  313.       me->state = SKIP_GET_VALUE;
  314.       /* Fall through! */
  315.       goto fall_through;
  316.     case LOCATION:
  317.       me->field = me->state;
  318.       me->state = SKIP_GET_VALUE;
  319.       /* Fall through! */
  320.     fall_through:
  321.     case SKIP_GET_VALUE:
  322.       if (c == '\n')
  323.     {
  324.       me->fold_state = me->state;
  325.       me->state = NEWLINE;
  326.       break;
  327.     }
  328.       if (WHITE(c))
  329.     break;    /* Skip white space */
  330.  
  331.       me->value_pointer = me->value;
  332.       me->state = GET_VALUE;
  333.       /* Fall through to store first character */
  334.  
  335.     case GET_VALUE:
  336.       if (WHITE(c))
  337.     {
  338.       /* End of field */
  339.       *me->value_pointer = 0;
  340.       switch (me->field)
  341.         {
  342.         case CONTENT_TYPE:
  343.           if (TRACE)
  344.         fprintf (stderr, "[MIME_put_char] Got content-type value '%s'\n", me->value);
  345.           /* Lowercase it. */
  346.           {
  347.         char *tmp;
  348.         for (tmp = me->value; *tmp; tmp++)
  349.           *tmp = TOLOWER (*tmp);
  350.           }
  351.           if (TRACE)
  352.         fprintf (stderr, "[MIME_put_char] Lowercased to '%s'\n", me->value);
  353.           me->format = HTAtom_for(me->value);
  354.           if (TRACE)
  355.         fprintf (stderr, "[MIME_put_char] Got content-type value atom 0x%08x\n",
  356.              me->format);
  357.           break;
  358.         case CONTENT_TRANSFER_ENCODING:
  359.           me->encoding = HTAtom_for(me->value);
  360.           if (TRACE)
  361.         fprintf (stderr,
  362.              "[MIME_put_char] Picked up transfer_encoding '%s'\n",
  363.              me->encoding);
  364.           break;
  365.         case CONTENT_ENCODING:
  366.           me->compression_encoding = strdup (me->value);
  367.           if (TRACE)
  368.         fprintf (stderr,
  369.              "[MIME_put_char] Picked up compression encoding '%s'\n",
  370.              me->compression_encoding);
  371.           break;
  372.         case CONTENT_LENGTH:
  373.           me->content_length = atoi (me->value);
  374.           /* This is TEMPORARY. */
  375.           loading_length = me->content_length;
  376.           if (TRACE)
  377.         fprintf (stderr,
  378.              "[MIME_put_char] Picked up content length '%d'\n",
  379.              me->content_length);
  380.           break;
  381.         case LOCATION:
  382.           me->location = me->value;
  383.           redirecting_url = strdup (me->location);
  384.           if (TRACE)
  385.         fprintf
  386.           (stderr,
  387.            "[MIME_put_char] Picked up location '%s'\n", me->location);
  388.           break;
  389.         default:        /* Should never get here */
  390.           break;
  391.         }
  392.     }
  393.       else
  394.     {
  395.       if (me->value_pointer < me->value + VALUE_SIZE - 1)
  396.         {
  397.           *me->value_pointer++ = c;
  398.           break;
  399.         }
  400.       else
  401.         {
  402.           goto value_too_long;
  403.         }
  404.     }
  405.       /* Fall through */
  406.  
  407.     case JUNK_LINE:
  408.       if (c == '\n')
  409.     {
  410.       me->state = NEWLINE;
  411.       me->fold_state = me->state;
  412.     }
  413.       break;
  414.  
  415.     } /* switch on state*/
  416.  
  417.   return;
  418.  
  419.  value_too_long:
  420.   if (TRACE) fprintf(stderr,
  421.              "HTMIME: *** Syntax error. (string too long)\n");
  422.  
  423.  bad_field_name:                /* Ignore it */
  424.   me->state = JUNK_LINE;
  425.   return;
  426. }
  427.  
  428.  
  429.  
  430. /*    String handling
  431. **    ---------------
  432. **
  433. **    Strings must be smaller than this buffer size.
  434. */
  435. PRIVATE void HTMIME_put_string ARGS2(HTStream *, me, CONST char*, s)
  436. {
  437.   CONST char * p;
  438.   if (TRACE)
  439.     fprintf (stderr, "[HTMIME_put_string] Putting '%s'\n", s);
  440.   if (me->state == MIME_TRANSPARENT)        /* Optimisation */
  441.     {
  442.       if (TRACE)
  443.     fprintf (stderr, "[HTMIME_put_string] Doing transparent put_string\n");
  444.       (*me->targetClass.put_string)(me->target,s);
  445.     }
  446.   else if (me->state != MIME_IGNORE)
  447.     {
  448.       if (TRACE)
  449.     fprintf (stderr, "[HTMIME_put_string] Doing char-by-char put_character\n");
  450.       for (p=s; *p; p++)
  451.     HTMIME_put_character(me, *p);
  452.     }
  453.   else
  454.     {
  455.       if (TRACE)
  456.     fprintf (stderr, "[HTMIME_put_string] DOING NOTHING!\n");
  457.     }
  458.   return;
  459. }
  460.  
  461.  
  462. /*    Buffer write.  Buffers can (and should!) be big.
  463. **    ------------
  464. */
  465. PRIVATE void HTMIME_write ARGS3(HTStream *, me, CONST char*, s, int, l)
  466. {
  467.   CONST char * p;
  468.   if (TRACE)
  469.     fprintf (stderr, "[HTMIME_write] Putting %d bytes\n", l);
  470.   if (me->state == MIME_TRANSPARENT)        /* Optimisation */
  471.     {
  472.       if (TRACE)
  473.     fprintf (stderr, "[HTMIME_write] Doing transparent put_block\n");
  474.       (*me->targetClass.put_block)(me->target, s, l);
  475.     }
  476.   else if (me->state != MIME_IGNORE)
  477.     {
  478.       if (TRACE)
  479.     fprintf (stderr, "[HTMIME_write] Doing char-by-char put_character\n");
  480.       for (p=s; p < s+l; p++)
  481.     HTMIME_put_character(me, *p);
  482.     }
  483.   else
  484.     {
  485.       if (TRACE)
  486.     fprintf (stderr, "[HTMIME_write] DOING NOTHING!\n");
  487.     }
  488.   return;
  489. }
  490.  
  491.  
  492.  
  493.  
  494. /*    Free an HTML object
  495. **    -------------------
  496. **
  497. */
  498. PRIVATE void HTMIME_free ARGS1(HTStream *, me)
  499. {
  500.   if (!me->target)
  501.     {
  502.       if (TRACE)
  503.     fprintf (stderr, "[HTMIME_free] Caught case where we didn't get a target.\n");
  504.       if (TRACE)
  505.     fprintf (stderr, "  me 0x%08x, me->target 0x%08x\n", me, me->target);
  506.       me->format = HTAtom_for ("text/html");
  507.       me->target = HTStreamStack(me->format, me->targetRep, 0,
  508.                  me->sink, me->anchor);
  509.       if (TRACE)
  510.     fprintf (stderr, "  me->target->isa 0x%08x\n", me->target->isa);
  511.       if (TRACE)
  512.     fprintf (stderr, "  *me->target->isa 0x%08x\n", *me->target->isa);
  513.       me->targetClass = *me->target->isa;
  514.       (*me->targetClass.put_string) (me->target, "<H1>ERROR IN HTTP/1.0 RESPONSE</H1> The remote server returned a HTTP/1.0 response that Mosaic's MIME parser could not understand.  Please contact the server maintainer.<P> Sorry for the inconvenience,"
  515. "<P><ADDRESS>The Management</ADDRESS>");
  516.     }
  517.   if (me->target)
  518.     (*me->targetClass.free)(me->target);
  519.  
  520.   free(me);
  521.  
  522.   return;
  523. }
  524.  
  525. /*    End writing
  526. */
  527.  
  528. PRIVATE void HTMIME_end_document ARGS1(HTStream *, me)
  529. {
  530.   if (me->target)
  531.     (*me->targetClass.end_document)(me->target);
  532. }
  533.  
  534. PRIVATE void HTMIME_handle_interrupt ARGS1(HTStream *, me)
  535. {
  536.   me->interrupted = 1;
  537.  
  538.   /* Propagate interrupt message down. */
  539.   if (me->target)
  540.     (*me->targetClass.handle_interrupt)(me->target);
  541.  
  542.   return;
  543. }
  544.  
  545.  
  546.  
  547. /*    Structured Object Class
  548. **    -----------------------
  549. */
  550. PUBLIC CONST HTStreamClass HTMIME =
  551. {
  552.   "MIMEParser",
  553.   HTMIME_free,
  554.   HTMIME_end_document,
  555.   HTMIME_put_character,     HTMIME_put_string,
  556.   HTMIME_write,
  557.   HTMIME_handle_interrupt
  558.   };
  559.  
  560.  
  561. /*    Subclass-specific Methods
  562. **    -------------------------
  563. */
  564.  
  565. PUBLIC HTStream* HTMIMEConvert ARGS5(
  566.     HTPresentation *,    pres,
  567.     HTParentAnchor *,    anchor,
  568.     HTStream *,        sink,
  569.     HTFormat,        format_in,
  570.     int,            compressed)
  571. {
  572.     HTStream* me;
  573.  
  574.     me = malloc(sizeof(*me));
  575.     me->isa = &HTMIME;
  576.  
  577.     if (TRACE)
  578.       fprintf (stderr, "[HTMIMEConvert] HELLO!\n");
  579.  
  580.     me->sink = sink;
  581.     me->anchor = anchor;
  582.     me->target = NULL;
  583.     me->state = BEGINNING_OF_LINE;
  584.     me->format = WWW_PLAINTEXT;
  585.     me->targetRep = pres->rep_out;
  586.     me->boundary = 0;        /* Not set yet */
  587.     me->location = 0;
  588.     me->interrupted = 0;
  589.     me->encoding = 0;
  590.     me->compression_encoding = 0;
  591.     me->content_length = -1;
  592.     return me;
  593. }
  594.